﻿
namespace Huirui.Cavan.Core.Message
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Diagnostics.Contracts;
    using Huirui.Cavan.Core.Extension;

    /// <summary>
    ///     Extensions available on every place of the framework.
    /// </summary>
    public static class MessageExt
    {
        #region AddError
        /// <summary>
        ///     Fundamental ERROR handling. This will not only add the message with severity Error into the collection, it will do more!
        ///     Whenever exists at least 1 Message (during users request) with severity ERROR:
        ///     NO changes are persisted! (In fact, transaction.Rollback is called)
        ///     This brings you new ability - count on adding Error-Messages, that's enough as well as on Business as on Controller layer
        /// </summary>
        /// <param name = "repository">Messages List. </param>
        /// <param name = "reporter">The object instance, which reports this event (ususally 'this' is suitable)</param>
        /// <param name = "shortName">The short name.</param>
        /// <param name = "messageTemplate">Template to be used for 1) translating, 2) filling with template arguments. ("CannotAdd{0}{1}")</param>
        /// <param name = "arguments">The arguments to be used for filling the localized template.</param>
        public static IList<AppMessage> AddError(this IList<AppMessage> repository, IMessagesReporter reporter,
            string shortName, string messageTemplate, params object[] arguments)
        {
            Contract.Requires(reporter.Is(), " reporter IMessagesReporter must be not null ");
            Contract.Requires(!string.IsNullOrEmpty(messageTemplate), " Message Template cannot be null or empty ");
            Contract.Requires(!string.IsNullOrEmpty(shortName), " ShortName cannot be null or empty ");

            var message = new AppMessage(reporter, MessageSeverity.Error, shortName, messageTemplate, arguments);
            reporter.Log().Error(message.ToString());
            repository.Add(message);
            return repository;
        }
        #endregion AddError

        #region AddWarning
        /// <summary>
        ///     Adds the warning message to the repository.
        /// </summary>
        /// <param name = "repository">Messages List. </param>
        /// <param name = "reporter">The object instance, which reports this event (ususally 'this' is suitable)</param>
        /// <param name = "shortName">The short name.</param>
        /// <param name = "messageTemplate">Template to be used for 1) translating, 2) filling with template arguments. ("CannotAdd{0}{1}")</param>
        /// <param name = "arguments">The arguments to be used for filling the localized template.</param>
        public static IList<AppMessage> AddWarning(this IList<AppMessage> repository, IMessagesReporter reporter,
            string shortName, string messageTemplate, params object[] arguments)
        {
            Contract.Requires(reporter.Is(), " reporter IMessagesReporter must be not null ");
            Contract.Requires(!string.IsNullOrEmpty(messageTemplate), " Message Template cannot be null or empty ");
            Contract.Requires(!string.IsNullOrEmpty(shortName), " ShortName cannot be null or empty ");

            var message = new AppMessage(reporter, MessageSeverity.Warning, shortName, messageTemplate, arguments);
            reporter.Log().Warn(message.ToString());
            repository.Add(message);
            return repository;
        }
        #endregion AddWarning

        #region AddInfo
        /// <summary>
        ///     Adds the info message to the repository.
        /// </summary>
        /// <param name = "repository">Messages List. </param>
        /// <param name = "reporter">The object instance, which reports this event (ususally 'this' is suitable)</param>
        /// <param name = "shortName">The short name.</param>
        /// <param name = "messageTemplate">Template to be used for 1) translating, 2) filling with template arguments. ("CannotAdd{0}{1}")</param>
        /// <param name = "arguments">The arguments to be used for filling the localized template.</param>
        public static IList<AppMessage> AddInfo(this IList<AppMessage> repository, IMessagesReporter reporter,
            string shortName, string messageTemplate, params object[] arguments)
        {
            Contract.Requires(reporter.Is(), " reporter IMessagesReporter must be not null ");
            Contract.Requires(!string.IsNullOrEmpty(messageTemplate), " Message Template cannot be null or empty ");
            Contract.Requires(!string.IsNullOrEmpty(shortName), " ShortName cannot be null or empty ");

            var message = new AppMessage(reporter, MessageSeverity.Info, shortName, messageTemplate, arguments);
            reporter.Log().Debug(message.ToString());
            repository.Add(message);
            return repository;
        }
        #endregion AddInfo

        #region AddDebug
        /// <summary>
        ///     Adds the warning message to the repository.
        /// </summary>
        /// <param name = "repository">Messages List. </param>
        /// <param name = "reporter">The object instance, which reports this event (ususally 'this' is suitable)</param>
        /// <param name = "shortName">The short name.</param>
        /// <param name = "messageTemplate">Template to be used for 1) translating, 2) filling with template arguments. ("CannotAdd{0}{1}")</param>
        /// <param name = "arguments">The arguments to be used for filling the localized template.</param>
        public static IList<AppMessage> AddDebug(this IList<AppMessage> repository, IMessagesReporter reporter,
            string shortName, string messageTemplate, params object[] arguments)
        {
            Contract.Requires(reporter.Is(), " reporter IMessagesReporter must be not null ");
            Contract.Requires(!string.IsNullOrEmpty(messageTemplate), " Message Template cannot be null or empty ");
            Contract.Requires(!string.IsNullOrEmpty(shortName), " ShortName cannot be null or empty ");

            var message = new AppMessage(reporter, MessageSeverity.Debug, shortName, messageTemplate, arguments);
            reporter.Log().Info(message.ToString());
            repository.Add(message);
            return repository;
        }
        #endregion AddDebug

        #region AddException
        /// <summary>
        ///     Fundamental EXCEPTION (Similar as ERROR) handling. This will not only add the message with severity Error into the collection, it will do more!
        ///     Whenever exists at least 1 Message (during users request) with severity ERROR:
        ///     NO changes are persisted! (In fact, transaction.Rollback is called)
        ///     This brings you new ability - count on adding Error-Messages, that's enough as well as on Business as on Controller layer
        ///     Adds the exception as the error message to the repository.
        /// </summary>
        /// <param name = "repository">Messages List. </param>
        /// <param name = "reporter">The object instance, which reports this event (ususally 'this' is suitable)</param>
        /// <param name = "shortName">The short name.</param>
        /// <param name = "ex">The ex.</param>
        public static IList<AppMessage> AddException(this IList<AppMessage> repository, IMessagesReporter reporter,
            string shortName, Exception ex)
        {
            Contract.Requires(reporter.Is(), " reporter IMessagesReporter must be not null ");
            Contract.Requires(!string.IsNullOrEmpty(shortName), " ShortName cannot be null or empty ");
            Contract.Requires(ex.Is(), " Exception cannot be null or empty ");

            var message = new AppMessage(reporter, MessageSeverity.Error, shortName, ex.Message)
            {
                AdditionalData = ex
            };
            reporter.Log().Fatal(message.ToString(), ex);
            repository.Add(message);
            return repository;
        }
        #endregion AddException

        #region ContainsError
        /// <summary>
        ///     Determines whether [contains any error] [the specified repository].
        /// </summary>
        /// <param name = "repository">The repository.</param>
        /// <returns>
        ///     <c>true</c> if [contains any error] [the specified repository]; otherwise, <c>false</c>.
        /// </returns>
        public static bool ContainsError(this IList<AppMessage> repository)
        {
            return repository.Any(msg => msg.Severity == MessageSeverity.Error);
        }
        #endregion ContainsError
    }
}